﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.DirectoryServices;
using System.Linq;
using System.Xml.Linq;
using LiveWebServiceBase.AOPLogWriter;
using LiveWebServiceBase.ReturnedTypes;
using Microsoft.Win32;
using System.Security.Permissions;

namespace LiveWebServiceBase
{
    public abstract class Settings
    {
        public static readonly string _solutionname = "Edu Fellows Web Service";

        public abstract class Logging
        {
            private static object objLock = new object();

            private static RegistryKey _regkey;
            private static RegistryKey regkey
            {
                get
                {
                    lock (objLock)
                    {
                        if (_regkey == null)
                        {
                            _regkey = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\LiveWebService");
                        }

                        return _regkey;
                    }
                }
            }

            public class LogItem
            {
                public TimeSpan ExecutionTime;
                public string ServiceUserName;
                public string ClientIP;
                public string LiveID;
                public string MethodName;
                public List<string> Arguments;
                public string ReturnValue;
                public bool IsSuccessed;
                public string ExceptionMessage;
                public string ExceptionSource;
                public EventLogEntryType LogEntryType;

                public void WriteLogRecord()
                {
                    //CreateLogRecord(this);
                    AsyncWriteLogRecord caller = new AsyncWriteLogRecord(CreateLogRecord);
                    caller.BeginInvoke(this, null, null);
                }
            }

            public static string DBConnectionString
            {
                get
                {
                    if (regkey != null)
                        return regkey.GetValue("Connection String").ToString().TrimEnd('\\');
                    else
                        throw new Exception("Can't find connection string to Log database in registry.");
                }
            }

            public static double EntryLifetime
            {
                get
                {
                    if (regkey != null)
                        return Convert.ToDouble(regkey.GetValue("LogEntryTime"));
                    else
                        throw new Exception("Can't find connection string to Log database in registry.");
                }
            }

            public static bool IsEnableLogging
            {
                get
                {
                    try
                    {
                        if (regkey != null)
                            return string.IsNullOrEmpty(regkey.GetValue("EnableLogging").ToString()) ? false : true;
                        else
                            throw new Exception("Can't find 'EnableLogging' key in registry.");
                    }
                    catch
                    {
                        return false;
                    }
                }
            }

            private static void CreateLogRecord(LogItem liItem)
            {
                EventLog myLog = new EventLog();

                if (!EventLog.SourceExists(_solutionname))
                {
                    EventLog.CreateEventSource(_solutionname, _solutionname);
                    System.Threading.Thread.Sleep(10000);
                }


                myLog.Source = _solutionname;

                myLog.WriteEntry(string.Format(" Service User '{0}' from '{1}' called method '{2}' with result: {3} \r\n\r\n (Execution time: {4} sec) with arguments: \r\n\r\n {5} \r\n\r\n {6} \r\n\r\n {7} \r\n\r\n (LiveID: {8})",
                    liItem.ServiceUserName,
                    liItem.ClientIP,
                    liItem.MethodName,
                    liItem.ReturnValue,
                    liItem.ExecutionTime.TotalSeconds,
                    string.Join(Environment.NewLine, liItem.Arguments),
                    (liItem.IsSuccessed ? string.Empty : "Exception message: " + liItem.ExceptionMessage),
                    (liItem.IsSuccessed ? string.Empty : "Exception source: " + liItem.ExceptionSource),
                    liItem.LiveID),
                    liItem.LogEntryType);
            }

            private delegate void AsyncWriteLogRecord(LogItem liItem);
        }

        public abstract class Paths
        {
            public static string PathToConfigDir
            {
                get
                {
                    return RootDirectoryPath + "\\config";
                }
            }

            public static string PathToPSConfigXML
            {
                get
                {
                    return PathToConfigDir + "\\ps_commands.xml";
                }
            }

            public static string PathToEWSConfigXML
            {
                get
                {
                    return PathToConfigDir + "\\ews_urls.xml";
                }
            }

            public static string PathToELMSConfigXML
            {
                get
                {
                    return PathToConfigDir + "\\elms_urls.xml";
                }
            }

            public static string PathToSSOConfigXML
            {
                get
                {
                    return PathToConfigDir + "\\sso_urls.xml";
                }
            }

            public static string RootDirectoryPath
            {
                get
                {
                    RegistryKey regkey = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\LiveWebService");

                    if (regkey != null)
                        return regkey.GetValue("Install directory").ToString().TrimEnd('\\');
                    else
                        throw new Exception("Can't find install path in registry.");
                }
            }
        }

        public abstract class ELMSVariables
        {
            private static object objLock = new object();

            private static string _cgiConnectorUrl = null;
            public static string cgiConnectorUrl
            {
                get
                {
                    lock (objLock)
                    {
                        if (_cgiConnectorUrl == null)
                        {
                            XDocument elmsSettings = XDocument.Load(Paths.PathToELMSConfigXML);

                            if (elmsSettings.Root.Element("cgiConnectorUrl").IsEmpty)
                                throw new Exception("Element 'cgiConnectorUrl' in 'elms_urls.xml' file is empty or didn't exists.");
                            else
                                _cgiConnectorUrl = elmsSettings.Root.Element("cgiConnectorUrl").Value;
                        }

                        return _cgiConnectorUrl;
                    }
                }
            }

            private static string _loginUrl;
            public static string loginUrl
            {
                get
                {
                    lock (objLock)
                    {
                        if (_loginUrl == null)
                        {
                            XDocument elmsSettings = XDocument.Load(Paths.PathToELMSConfigXML);

                            if (elmsSettings.Root.Element("loginUrl").IsEmpty)
                                throw new Exception("Element 'loginUrl' in 'elms_urls.xml' file is empty or didn't exists.");
                            else
                                _loginUrl = elmsSettings.Root.Element("loginUrl").Value;
                        }

                        return _loginUrl;
                    }
                }
            }
        }

        public abstract class EWSVariables
        {
            private static object objLock = new object();

            private static List<string> _ServiceURLs;
            public static List<string> ServiceURLs
            {
                get
                {
                    lock (objLock)
                    {
                        if (_ServiceURLs == null)
                        {
                            XDocument ewsSettings = XDocument.Load(Paths.PathToEWSConfigXML);
                            _ServiceURLs = ewsSettings.Root.Descendants("item").Select(le => le.Attribute("value").Value).ToList();
                        }

                        return _ServiceURLs;
                    }
                }
            }

            public static int GetCountServiceURLs()
            {
                return ServiceURLs.Count();
            }

            public static string GetServiceURL(int index)
            {
                return ServiceURLs[index];
            }
        }

        public abstract class PSVariables
        {
            private static object objLock = new object();

            private static DateTime dtLastReaded;
            private static Dictionary<string, List<string>> _PSCommands;
            public static Dictionary<string, List<string>> PSCommands
            {
                get
                {
                    lock (objLock)
                    {
                        System.IO.FileInfo fi = new System.IO.FileInfo(Paths.PathToPSConfigXML);

                        if (_PSCommands == null || dtLastReaded.CompareTo(fi.LastWriteTime) <= 0)
                        {
                            _PSCommands = new Dictionary<string, List<string>>();

                            XDocument psSettings = XDocument.Load(Paths.PathToPSConfigXML);

                            dtLastReaded = DateTime.Now;

                            var ps_commands = psSettings.Root.Descendants().Where(le => le.HasElements).ToList();

                            foreach (var ps_command in ps_commands)
                            {
                                var ps_text = ps_command.Descendants("command").Where(A => A.Parent.Name == ps_command.Name).Select(A => A.Value).ToList<string>();
                                _PSCommands.Add(ps_command.Name.ToString(), ps_text);
                            }
                        }

                        return _PSCommands;
                    }
                }
            }
        }

        public abstract class LiveEduServiceURLs
        {
            private static object objLock = new object();

            private static Dictionary<RedirectType, string> _redirectTypeDictionary;
            public static Dictionary<RedirectType, string> redirectTypeDictionary
            {
                get
                {
                    lock (objLock)
                    {
                        if (_redirectTypeDictionary == null)
                        {
                            XDocument ssoSettings = XDocument.Load(Paths.PathToSSOConfigXML);

                            Dictionary<RedirectType, string> tmp = new Dictionary<RedirectType, string>();

                            foreach (var item in ssoSettings.Root.Descendants("item"))
                                tmp.Add((RedirectType)Enum.Parse(typeof(RedirectType), item.Attribute("RedirectType").Value), item.Attribute("url").Value);

                            _redirectTypeDictionary = tmp;

                        }

                        return _redirectTypeDictionary;
                    }
                }
            }
        }

        public abstract class UserInfo
        {
            public static readonly string adminGroupName = "EFMSAdministrators";
            public static readonly string userGroupName = "EFMSUsers";

            public static bool IsAdminUser(string Username)
            {
                List<string> lstGroupUsers = GetGroupUsers(adminGroupName);

                if (lstGroupUsers.Count(le => le.Contains(Username.ToLower())) == 1)
                    return true;

                return false;
            }

            public static bool IsServiceUser(string Username)
            {
                List<string> lstGroupUsers = GetGroupUsers(userGroupName);

                if (lstGroupUsers.Count(le => le.Contains(Username.ToLower())) == 1)
                    return true;

                return false;
            }

            public static List<string> GetGroupUsers(string GroupName)
            {
                List<string> lstUser = new List<string> { };
                DirectoryEntry AD = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");

                DirectoryEntry groupEntry = AD.Children.Add(GroupName, "group");

                if (groupEntry == null)
                    throw new Exception("Can't find group: " + GroupName);

                foreach (object obj in (IEnumerable)groupEntry.Invoke("members"))
                {
                    using (DirectoryEntry user = new DirectoryEntry(obj))
                    {
                        lstUser.Add((Environment.MachineName + "\\" + user.Name).ToLower());
                    }
                }

                return lstUser;
            }

            public static string GetUserName(string FullUserName)
            {
                if (FullUserName.Contains('\\'))
                    return FullUserName.Split('\\')[1];
                else
                    return FullUserName;
            }
        }
    }
}
